package com.yn.sample.util;

import java.util.Arrays;
import java.util.Objects;

public enum OpCodeEnum {
    /**
     * 加载常量整数1到操作数栈
     */
    iconst_1("iconst_1","加载常量整数1到操作数栈"),

    /**
     * 0x2a aload_0 将第一个引用类型局部变量推送至栈顶。
     */
    aload_0("aload_0","0x2a aload_0 将第一个引用类型局部变量推送至栈顶。"),

    /**
     * 0xb7 invokespecial 调用超类构造方法，实例初始化方法，私有方法。
     */
    invokespecial("invokespecial","0xb7 invokespecial 调用超类构造方法，实例初始化方法，私有方法。操作数栈：objectref，[arg1，[arg2 …]] →"),



    /**
     * 将栈顶元素出栈，保存到本地变量表的slot2（索引从0开始）
     *
     * istore_<n>
     *
     * <n>必须是一个指向当前栈帧（§2.6）局部变量表的索引值，而在操作数栈
     * 栈顶的 value 必须是 int 类型的数据，这个数据将从操作数栈出栈， 然后保
     * 存到<n>所指向的局部变量表位置中。
     */
    istore_2("istore_2","将栈顶元素出栈，保存到本地变量表的slot2（索引从0开始）"),

    istore_3("istore_3","将栈顶元素出栈，保存到本地变量表的slot3（索引从0开始）"),

    /**
     * 0x1b iload_1 将索引为1的局部变量推送至栈顶。
     */
    iload_1("iload_1","将索引为1的局部变量推送至栈顶。"),

    /**
     * 0x1b iload_2 将索引为2的局部变量推送至栈顶。
     */
    iload_2("iload_2","将索引为2的局部变量推送至栈顶。"),

    iload_3("iload_3","将索引为3的局部变量推送至栈顶。"),

    /**
     * 0x9b iflt 当栈顶 int 型数值小于 0 时跳转。
     */
    iflt("iflt","将栈顶元素出栈，与0比较，如果结果小于 0 时跳转。"),

    /**
     * 跳转指令
     */
    GOTO("GOTO","跳转指令"),

    /**
     * 推送常量0，到栈顶
     */
    iconst_0("iconst_0","推送常量0，到栈顶"),


    /**
     * 返回语句
     */
    RETURN("RETURN","返回语句"),

    ireturn("ireturn","结束方法，并返回一个 int 类型数据,栈顶元素从当前栈帧中出栈， 然后压入" +
            "到调用者栈帧的操作数栈中"),

    putfield("putfield","从栈顶依次弹出要设置的参数值value、要设置field的目标对象objectref；" +
            "然后从该putfield的操作数中，取到要修改的filed引用;然后将value赋值到objectref的对应field中"),
    NEW("new","新建一个对象，压入栈顶"),
    dup("dup","复制栈顶对象，压入堆栈"),
    athrow("athrow","将栈顶的引用出栈，该引用是一个Throwable类型的实例的引用，在当前栈帧内寻找异常处理器，" +
            "找不到就抛出异常;找到就丢给异常处理器去处理"),

    ldc("ldc","将 int， float 或 String 型常量值从常量池中推送至栈顶"),

    bipush("bipush","将单字节的常量值（-128~127） 推送至栈顶"),
    ;

    private String opCode;

    private String desc;

    OpCodeEnum(String opCode, String desc) {
        this.opCode = opCode;
        this.desc = desc;
    }

    public String getOpCode() {
        return opCode;
    }

    public String getDesc() {
        return desc;
    }

    public static String getDescByNameIgnoreCase(String name){
        OpCodeEnum target = Arrays.stream(OpCodeEnum.values()).filter(opCodeEnum ->
                Objects.equals(opCodeEnum.getOpCode().toLowerCase(), name.toLowerCase()))
                .findFirst().orElse(null);
        if (target == null) {
            throw new RuntimeException();
        }

        String desc = target.getDesc();
        return desc;
    }
}
